﻿using FreeSql.Internal.CommonProvider;
using FreeSql.Internal;
using Microsoft.Extensions.DependencyInjection;
using System.Linq.Expressions;
using System.Reflection;

namespace FreeSql
{
    public static class FreeSqlExtension
    {

        #region MyRegion
        /// <summary>
        /// 手工创建分表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="this"></param>
        public static void CreateTable<T>(this IFreeSql @this)
        {
            CreateTable(@this, typeof(T));
        }

        /// <summary>
        /// 手工创建分表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="this"></param>
        public static void CreateTable(this IFreeSql @this, Type t, bool sync = false)
        {
            var tb = @this.CodeFirst.GetTableByEntity(t);
            var tableName = tb.AsTableImpl.GetTableNameByColumnValue(DateTime.Now, true);
            if (!Tables.Contains(tableName))
            {
                var table = @this.DbFirst.GetTableByName(tableName);
                if (table == null)
                {
                    @this.CodeFirst.SyncStructure(t, tableName);
                    Tables.Add(tableName);
                }
                else
                {
                    if (sync) @this.CodeFirst.SyncStructure(t, tableName);
                    Tables.Add(tableName);
                }
            }
        }

        /// <summary>
        /// 手工创建分表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="this"></param>
        public static void CreateTable(this IFreeSql @this, Type t, DateTime date, bool sync = false)
        {
            var tb = @this.CodeFirst.GetTableByEntity(t);
            var tableName = tb.AsTableImpl.GetTableNameByColumnValue(date, true);
            if (!Tables.Contains(tableName))
            {
                var table = @this.DbFirst.GetTableByName(tableName);
                if (table == null)
                {
                    @this.CodeFirst.SyncStructure(t, tableName);
                    Tables.Add(tableName);
                }
                else
                {
                    if (sync) @this.CodeFirst.SyncStructure(t, tableName);
                    Tables.Add(tableName);
                }
            }
        }


        public static void CreateTableAddMonth(this IFreeSql @this, Type t, bool sync = false)
        {
            var tb = @this.CodeFirst.GetTableByEntity(t);
            var tableName = tb.AsTableImpl.GetTableNameByColumnValue(DateTime.Now.AddMonths(1), true);
            if (!Tables.Contains(tableName))
            {
                var table = @this.DbFirst.GetTableByName(tableName);
                if (table == null)
                {
                    @this.CodeFirst.SyncStructure(t, tableName);
                    Tables.Add(tableName);
                }
                else
                {
                    if (sync) @this.CodeFirst.SyncStructure(t, tableName);
                    Tables.Add(tableName);
                }
            }
        }


        /// <summary>
        /// 手工创建分表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="this"></param>
        public static void CreateTableAddMonth<T>(this IFreeSql @this)
        {
            CreateTableAddMonth(@this, typeof(T));
        }

        public static HashSet<string> Tables { get; set; } = new HashSet<string>();


        /// <summary>
        /// 手工创建分表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="this"></param>
        /// <param name="fieldDateValue">日期</param>
        public static void CreateTable<T>(this IFreeSql @this, DateTime fieldDateValue, bool sync = false)
        {

            var tb = @this.CodeFirst.GetTableByEntity(typeof(T));
            var tableName = tb.AsTableImpl.GetTableNameByColumnValue(fieldDateValue, true);
            if (!Tables.Contains(tableName))
            {
                var table = @this.DbFirst.GetTableByName(tableName);
                if (table == null)
                {
                    @this.CodeFirst.SyncStructure(typeof(T), tableName);
                    Tables.Add(tableName);
                }
                else
                {
                    if (sync) @this.CodeFirst.SyncStructure(typeof(T), tableName);
                    Tables.Add(tableName);
                }
            }
        }



        #endregion

        #region MyRegion
        #region MyRegion
        /// <summary>
        /// 修正结束日期，改为当日的23:59秒
        /// </summary>
        /// <param name="dateTime"></param>
        /// <param name=""></param>
        /// <returns></returns>
        public static DateTime FixedEndDate(this DateTime? dateTime)
        {
            if (dateTime == null || dateTime == default(DateTime)) return DateTime.Now.Date.AddDays(1).AddSeconds(-1); ;
            return dateTime.Value.Date.AddDays(1).AddSeconds(-1);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static DateTime FixedEndDate(this DateTime dateTime)
        {
            return dateTime.Date.AddDays(1).AddSeconds(-1);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dates"></param>
        /// <returns></returns>
        public static List<DateTime> FixedDates(this List<DateTime?>? dates)
        {
            if (dates == null)
            {
                return new List<DateTime> { DateTime.Now.Date, new Nullable<DateTime>().FixedEndDate() };
            }
            if (dates.Count != 2)
            {
                return new List<DateTime> { DateTime.Now.Date, new Nullable<DateTime>().FixedEndDate() };
            }

            if (dates[0].GetValueOrDefault() < DbConfig.DbBegDate)
            {
                dates[0] = DbConfig.DbBegDate;
            }

            if (dates[1].FixedEndDate() > DateTime.Now.AddMonths(1))
            {
                dates[1] = DateTime.Now.AddMonths(1);
            }

            return new List<DateTime> { dates[0] == null ? DateTime.Now.Date : dates[0].GetValueOrDefault(), dates[1] == null ? new Nullable<DateTime>().FixedEndDate() : dates[1].FixedEndDate() };
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dates"></param>
        /// <returns></returns>
        public static List<DateTime> FixedDates(this List<DateTime>? dates)
        {
            if (dates == null)
            {
                return new List<DateTime> { DateTime.Now.Date, new Nullable<DateTime>().FixedEndDate() };
            }
            if (dates.Count != 2)
            {
                return new List<DateTime> { DateTime.Now.Date, new Nullable<DateTime>().FixedEndDate() };
            }
            if (dates[0].Date < DbConfig.DbBegDate)
            {
                dates[0] = DbConfig.DbBegDate;
            }

            if (dates[1].FixedEndDate() > DateTime.Now.AddMonths(1))
            {
                dates[1] = DateTime.Now.AddMonths(1);
            }
            return new List<DateTime> { dates[0].Date != dates[0] ? dates[0] : dates[0].Date, dates[1].Date != dates[1] ? dates[1] : dates[1].FixedEndDate() };
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dates"></param>
        /// <returns></returns>
        public static List<DateTime> FixedDates(this DateTime[]? dates)
        {
            if (dates == null)
            {
                return new List<DateTime> { DateTime.Now.Date, new Nullable<DateTime>().FixedEndDate() };
            }
            if (dates.Length != 2)
            {
                return new List<DateTime> { DateTime.Now.Date, new Nullable<DateTime>().FixedEndDate() };
            }

            if (dates[0].Date < DbConfig.DbBegDate)
            {
                dates[0] = DbConfig.DbBegDate;
            }

            if (dates[1].FixedEndDate() > DateTime.Now.AddMonths(1))
            {
                dates[1] = DateTime.Now.AddMonths(1);
            }
            return new List<DateTime> { dates[0].Date != dates[0] ? dates[0] : dates[0].Date, dates[1].Date != dates[1] ? dates[1] : dates[1].FixedEndDate() };
        }
        /// <summary>
        /// 获取开始日期和结束日期之间每个月的1号
        /// </summary>
        /// <param name="start">开始日期</param>
        /// <param name="end">结束日期</param>
        /// <returns>每个月1号的日期列表</returns>
        public static List<DateTime> GetMonths(this DateTime start, DateTime end)
        {
            var result = new List<DateTime>();
            // 取开始月的1号
            var current = new DateTime(start.Year, start.Month, 1);
            // 取结束月的1号
            var endMonth = new DateTime(end.Year, end.Month, 1);

            while (current <= endMonth)
            {
                result.Add(current);
                current = current.AddMonths(1);
            }
            return result;
        }
        /// <summary>
        /// 获取间隔的每月
        /// </summary>
        /// <param name="dates"></param>
        /// <returns></returns>
        public static List<DateTime> GetMonths(this List<DateTime> dates)
        {
            List<DateTime> moths = new List<DateTime>();
            var begDate = new DateTime(dates[0].Year, dates[0].Month, 1);
            while (true)
            {
                if (begDate > dates[1])
                {
                    break;
                }
                moths.Add(begDate);
                begDate = begDate.AddMonths(1);
            }

            return moths;
        }
        #endregion

        #region 手工分表处理
        /// <summary>
        /// 单个表只用于插入，修改，删除情况切换表格
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="resp"></param>
        /// <param name="date">日期，自动转化为按月</param>
        public static IBaseRepository<T> AsSingleTable<T>(this IBaseRepository<T> resp, DateTime date) where T : class
        {
            //   resp.AsTable((s) => $"{s.Replace("{yyyyMM}", date.ToString("yyyyMM"))}");
            resp.AsTable((s) => $"{s}_{date.ToString("yyyyMM")}");
            return resp;
        }
        /// <summary>
        /// 单个表只用于插入，修改，删除情况切换表格
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="resp"></param>
        /// <param name="con"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        public static IBaseRepository<T> AsSingleTableIf<T>(this IBaseRepository<T> resp, bool con, DateTime date) where T : class
        {
            if (con)
                resp.AsTable((s) => $"{s}_{date.ToString("yyyyMM")}");
            else resp.AsTable((s) => s);
            return resp;
        }

        /// <summary>
        /// 单个表只用于插入，修改，删除情况切换表格
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="resp"></param>
        /// <returns></returns>
        public static IBaseRepository<T> AsSingleTable<T>(this IBaseRepository<T> resp) where T : class
        {
            //   resp.AsTable((s) => $"{s.Replace("{yyyyMM}", date.ToString("yyyyMM"))}");
            resp.AsTable((s) => s);
            return resp;
        }

        /*  /// <summary>
          /// 
          /// </summary>
          /// <typeparam name="T"></typeparam>
          /// <param name="resp"></param>
          /// <returns></returns>
          public static IBaseRepository<T> AsTable<T>(this IBaseRepository<T> resp) where T : class
          {
              // resp.AsTable((s) => $"{s.Replace("_{yyyyMM}", "")}");
              return resp;
          }*/

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="resp"></param>
        /// <param name="tableName">表名的后缀，如按月则202201</param>
        public static IBaseRepository<T> AsTable<T>(this IBaseRepository<T> resp, string tableName) where T : class
        {

            resp.AsTable((s) => $"{s}_{tableName}");
            return resp;
        }

        /// 
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <param name="that"></param>
        /// <param name="cond"></param>
        /// <param name="pathSelector"></param>
        /// <param name="up"></param>
        /// <param name="pathSeparator"></param>
        /// <param name="level"></param>
        /// <returns></returns>
        public static ISelect<T1> AsTreeCteIf<T1>(this ISelect<T1> that, bool cond, Expression<Func<T1, string>> pathSelector = null, bool up = false, string pathSeparator = " -> ", int level = -1) where T1 : class
        {

            if (cond)
                return that.AsTreeCte(pathSelector, up, pathSeparator, level);
            else return that;
        }

        /// <summary>
        /// 原表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <returns></returns>
        public static ISelect<T> AsTable<T>(this ISelect<T> select)
        {
            return select.AsTable((t, s) => $"{s}");
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <param name="cond"></param>
        /// <returns></returns>
        public static ISelect<T> AsTableIf<T>(this ISelect<T> select, bool cond)
        {
            if (cond)
            {
                return select.AsTable((t, s) => $"{s}");
            }
            return select;
        }
        public static ISelect<T> AsTableIf<T>(this ISelect<T> select, bool cond, DateTime date)
        {
            if (cond)
            {
                return AsTable(select, date);
            }
            return select;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        public static ISelect<T> AsTable<T>(this ISelect<T> select, DateTime date)
        {

            date = new DateTime(date.Year, date.Month, 1);
            if (date > DateTime.Now.AddDays(1).Date)
            {
                return select;
            }
            else if (date < DbConfig.DbBegDate)
            {
                return select;
            }

            return select.AsTable((t, s) =>
            {

                if (t == typeof(T))
                {
                    return $"{s}_{date.ToString("yyyyMM")}";
                }
                return $"{s}";
            });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="select"></param>
        /// <param name="cond"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        public static ISelect<T> AsTableIf<T, T2>(this ISelect<T> select, bool cond, DateTime date)
        {
            if (cond)
            {
                return AsTable(select, date);
            }
            return select;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="select"></param>
        /// <param name="date"></param>
        /// <returns></returns>

        public static ISelect<T> AsTable<T, T2>(this ISelect<T> select, DateTime date)
        {
            date = new DateTime(date.Year, date.Month, 1);
            if (date > DateTime.Now.AddDays(1).Date)
            {
                return select;
            }
            else if (date < DbConfig.DbBegDate)
            {
                return select;
            }
            return select.AsTable((t, s) =>
            {

                if (t == typeof(T) || t == typeof(T2))
                {
                    return $"{s}_{date.ToString("yyyyMM")}";
                }
                return $"{s}";
            });
            // return select.AsTable((t, s) => $"{s.Replace("{yyyyMM}", date.ToString("yyyyMM"))}");
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="T3"></typeparam>
        /// <param name="select"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        public static ISelect<T> AsTable<T, T2, T3>(this ISelect<T> select, DateTime date)
        {
            date = new DateTime(date.Year, date.Month, 1);
            if (date > DateTime.Now.AddDays(1).Date)
            {
                return select;
            }
            else if (date < DbConfig.DbBegDate)
            {
                return select;
            }
            return select.AsTable((t, s) =>
            {

                if (t == typeof(T) || t == typeof(T2) || t == typeof(T3))
                {
                    return $"{s}_{date.ToString("yyyyMM")}";
                }
                return $"{s}";
            });
            // return select.AsTable((t, s) => $"{s.Replace("{yyyyMM}", date.ToString("yyyyMM"))}");
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="T3"></typeparam>
        /// <typeparam name="T4"></typeparam>
        /// <param name="select"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        public static ISelect<T> AsTable<T, T2, T3, T4>(this ISelect<T> select, DateTime date)
        {
            date = new DateTime(date.Year, date.Month, 1);

            if (date > DateTime.Now.AddDays(1).Date)
            {
                return select;
            }
            else if (date < DbConfig.DbBegDate)
            {
                return select;
            }
            return select.AsTable((t, s) =>
            {

                if (t == typeof(T) || t == typeof(T2) || t == typeof(T3) || t == typeof(T4))
                {
                    return $"{s}_{date.ToString("yyyyMM")}";
                }
                return $"{s}";
            });
            // return select.AsTable((t, s) => $"{s.Replace("{yyyyMM}", date.ToString("yyyyMM"))}");
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="T3"></typeparam>
        /// <typeparam name="T4"></typeparam>
        /// <typeparam name="T5"></typeparam>
        /// <param name="select"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        public static ISelect<T> AsTable<T, T2, T3, T4, T5>(this ISelect<T> select, DateTime date)
        {
            date = new DateTime(date.Year, date.Month, 1);

            if (date > DateTime.Now.AddDays(1).Date)
            {
                return select;
            }
            else if (date < DbConfig.DbBegDate)
            {
                return select;
            }
            return select.AsTable((t, s) =>
            {

                if (t == typeof(T) || t == typeof(T2) || t == typeof(T3) || t == typeof(T4) || t == typeof(T5))
                {
                    return $"{s}_{date.ToString("yyyyMM")}";
                }
                return $"{s}";
            });
            // return select.AsTable((t, s) => $"{s.Replace("{yyyyMM}", date.ToString("yyyyMM"))}");
        }


        public static ISelect<T> AsTableIf<T>(this ISelect<T> select, bool cond, DateTime begDate, DateTime endDate)
        {
            if (cond)
            {
                return AsTable(select, begDate, endDate);
            }
            return select;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <param name="begDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public static ISelect<T> AsTable<T>(this ISelect<T> select, DateTime begDate, DateTime endDate)
        {
            var date = new DateTime(begDate.Year, begDate.Month, 1);
            while (true)
            {
                select = select.AsTable(date);

                if (new DateTime(date.Year, date.Month, 1) < new DateTime(endDate.Year, endDate.Month, 1))
                {
                    date = date.AddMonths(1);
                }
                else
                {
                    break;
                }
            }
            return select;
        }
        public static ISelect<T> AsTableIf<T, T2>(this ISelect<T> select, bool cond, DateTime begDate, DateTime endDate)
        {

            if (cond)
            {
                return select.AsTable<T, T2>(begDate, endDate);
            }
            else return select;
        }

        public static ISelect<T> AsTableIf<T, T2, T3>(this ISelect<T> select, bool cond, DateTime begDate, DateTime endDate)
        {
            if (cond)
            {
                return select.AsTable<T, T2, T3>(begDate, endDate);
            }
            else return select;
        }

        public static ISelect<T> AsTable<T, T2>(this ISelect<T> select, DateTime begDate, DateTime endDate)
        {
            var date = new DateTime(begDate.Year, begDate.Month, 1);
            while (true)
            {
                select = select.AsTable<T, T2>(date);

                if (new DateTime(date.Year, date.Month, 1) < new DateTime(endDate.Year, endDate.Month, 1))
                {
                    date = date.AddMonths(1);
                }
                else
                {
                    break;
                }
            }
            return select;
        }

        public static ISelect<T> AsTable<T, T2, T3>(this ISelect<T> select, DateTime begDate, DateTime endDate)
        {
            var date = new DateTime(begDate.Year, begDate.Month, 1);
            while (true)
            {
                select = select.AsTable<T, T2, T3>(date);

                if (new DateTime(date.Year, date.Month, 1) < new DateTime(endDate.Year, endDate.Month, 1))
                {
                    date = date.AddMonths(1);
                }
                else
                {
                    break;
                }
            }
            return select;
        }


        public static ISelect<T> AsTable<T, T2, T3, T4>(this ISelect<T> select, DateTime begDate, DateTime endDate)
        {
            var date = new DateTime(begDate.Year, begDate.Month, 1);
            while (true)
            {
                select = select.AsTable<T, T2, T3, T4>(date);

                if (new DateTime(date.Year, date.Month, 1) < new DateTime(endDate.Year, endDate.Month, 1))
                {
                    date = date.AddMonths(1);
                }
                else
                {
                    break;
                }
            }
            return select;
        }


        public static ISelect<T> AsTable<T, T2, T3, T4, T5>(this ISelect<T> select, DateTime begDate, DateTime endDate)
        {
            var date = begDate;
            while (true)
            {
                select = select.AsTable<T, T2, T3, T4, T5>(date);

                if (new DateTime(date.Year, date.Month, 1) < new DateTime(endDate.Year, endDate.Month, 1))
                {
                    date = date.AddMonths(1);
                }
                else
                {
                    break;
                }
            }
            return select;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <param name="cond"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static ISelect<T> CountIf<T>(this ISelect<T> select, bool cond, out long count)
        {
            if (cond)
            {
                return select.Count(out count);
            }
            count = 0;
            return select;
        }
        #endregion


        #region 自动分表扩展处理

        /// <summary>
        /// 按月分表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <param name="date">日期</param>
        /// <returns></returns>
        public static ISelect<T> AsMonthTable<T>(this ISelect<T> select, DateTime date)
        {

            return select.AsTable((t, s) =>
            {
                return s.Replace("{yyyyMM}", date.ToString("yyyyMM"));
            });
        }


        public static ISelect<T> AsMonthTable<T, T2>(this ISelect<T> select, DateTime date)
        {

            return select.AsTable((t, s) =>
            {
                return s.Replace("{yyyyMM}", date.ToString("yyyyMM"));
            });
        }



        public static IUpdate<T> AsMonthTable<T>(this IUpdate<T> select, DateTime date)
        {
            return select.AsTable((s) => s.Replace("{yyyyMM}", date.ToString("yyyyMM")));
        }

        public static IUpdate<T> AsMonthTable<T>(this IUpdate<T> select, DateTime begDate, DateTime endDate)
        {
            var date = begDate;
            while (true)
            {
                select = select.AsMonthTable(date);

                if (new DateTime(date.Year, date.Month, 1) < new DateTime(endDate.Year, endDate.Month, 1))
                {
                    date = date.AddMonths(1);
                }
                else
                {
                    break;
                }
            }
            return select;
        }
        /// <summary>
        /// 按月分表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <param name="begDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public static ISelect<T> AsMonthTable<T>(this ISelect<T> select, DateTime begDate, DateTime endDate)
        {
            var date = begDate;
            while (true)
            {
                select = select.AsMonthTable(date);

                if (new DateTime(date.Year, date.Month, 1) < new DateTime(endDate.Year, endDate.Month, 1))
                {
                    date = date.AddMonths(1);
                }
                else
                {
                    break;
                }
            }

            return select;
        }


        public static IDelete<T> AsMonthTable<T>(this IDelete<T> select, DateTime date)
        {
            return select.AsTable((s) => s.Replace("{yyyyMM}", date.ToString("yyyyMM")));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <param name="begDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public static IDelete<T> AsMonthTable<T>(this IDelete<T> select, DateTime begDate, DateTime endDate)
        {
            var date = begDate;
            while (true)
            {
                select = select.AsMonthTable(date);

                if (new DateTime(date.Year, date.Month, 1) < new DateTime(endDate.Year, endDate.Month, 1))
                {
                    date = date.AddMonths(1);
                }
                else
                {
                    break;
                }
            }
            return select;
        }

        #endregion

        #region MyRegion

        #endregion
        /// <summary>
        /// 软删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="resp"></param>
        /// <param name="id"></param>
        /// <param name="userId"></param>
        /// <param name="userName"></param>
        /// <returns></returns>
        public static async Task<bool> SoftDeleteAsync<T, TKey>(this IBaseRepository<T> resp, TKey id, long userId, string userName) where T : class
        {
            var count = await resp.UpdateDiy
                 .SetDto(new { IsDeleted = true, UpdatedBy = userId, UpdatedByName = userName })
                 .WhereDynamic(id)
                 .ExecuteAffrowsAsync();
            return count > 0;
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static async Task<bool> SoftDeleteAsync<T>(this IBaseRepository<T> resp, Expression<Func<T, bool>> predicate, long userId, string userName) where T : class
        {
            var count = await resp.UpdateDiy
             .SetDto(new { IsDeleted = true, UpdatedBy = userId, UpdatedByName = userName })
            .Where(predicate)
             .ExecuteAffrowsAsync();
            return count > 0;
        }

        public static async Task<bool> SoftDeleteAsync<T, TKey>(this IBaseRepository<T> resp, TKey[] ids, long userId, string userName) where T : class
        {
            var count = await resp.UpdateDiy
            .SetDto(new { IsDeleted = true, UpdatedBy = userId, UpdatedByName = userName })
                 .WhereDynamic(ids)
                 .ExecuteAffrowsAsync();
            return count > 0;
        }





        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <returns></returns>
        public static List<T>? ToListOrDefault<T>(this ISelect<T> select)
        {

            var o = select.ToList();
            if (o == null)
            {
                return null;
            }
            return o;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <param name="con"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static ISelect<T> DisableGlobalFilterIf<T>(this ISelect<T> select, bool con, params string[] name)
        {
            if (con)
            {
                return select.DisableGlobalFilter(name);
            }
            return select;

        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static Task<List<T>?> ToListOrDefaultAsync<T>(this ISelect<T> select, CancellationToken cancellationToken = default)
        {

            var o = select.ToListAsync(cancellationToken);
            if (o == null)
            {
                return Task.FromResult<List<T>?>(null);
            }
#pragma warning disable CS8619 // 值中的引用类型的为 Null 性与目标类型不匹配。
            return o;
#pragma warning restore CS8619 // 值中的引用类型的为 Null 性与目标类型不匹配。
        }



        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <returns></returns>
        public static T? ToOneOrDefault<T>(this ISelect<T> select)
        {
            return select.ToOne<T?>();
        }


        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <returns></returns>
        public static T? FirstOrDefault<T>(this ISelect<T> select)
        {
            return select.First<T?>();
        }



        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static Task<T?> ToOneOrDefaultAsync<T>(this ISelect<T> select, CancellationToken cancellationToken = default)
        {
            return select.ToOneAsync<T?>(cancellationToken);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static Task<T?> FirstOrDefaultAsync<T>(this ISelect<T> select, CancellationToken cancellationToken = default)
        {

            return select.FirstAsync<T?>(cancellationToken);

        }
    }

    public static class MyFreeSqlExtensions
    {
        public static ISelect<T1> DisableGlobalAsTable<T1>(this ISelect<T1> that)
        {
            var s0p = (that as Select0Provider);
            if (s0p != null) s0p._tableRules.Clear();
            return that;
        }
        public static IInsert<T1> DisableGlobalAsTable<T1>(this IInsert<T1> that) where T1 : class
        {
            var s0p = (that as InsertProvider<T1>);
            if (s0p != null) s0p._tableRule = null;
            return that;
        }
        public static IUpdate<T1> DisableGlobalAsTable<T1>(this IUpdate<T1> that) where T1 : class
        {
            var s0p = (that as UpdateProvider<T1>);
            if (s0p != null) s0p._tableRule = null;
            return that;
        }
        public static IDelete<T1> DisableGlobalAsTable<T1>(this IDelete<T1> that) where T1 : class
        {
            var s0p = (that as DeleteProvider<T1>);
            if (s0p != null) s0p._tableRule = null;
            return that;
        }
        public static IInsertOrUpdate<T1> DisableGlobalAsTable<T1>(this IInsertOrUpdate<T1> that) where T1 : class
        {
            var s0p = (that as InsertOrUpdateProvider<T1>);
            if (s0p != null) s0p._tableRule = null;
            return that;
        }


        /// <summary>
        /// 加种子数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="_fsql"></param>
        /// <param name="data"></param>
        public static void HasData<T>(this IFreeSql _fsql, IEnumerable<T> data)
        {
            if (data.Any() == false) return;
            var sdCopy = data.Select(a => (object)a).ToList();
            var sdCopyLock = new object();

            object[] sd = null;
            lock (sdCopyLock)
                sd = sdCopy?.ToArray();
            if (sd == null || sd.Any() == false) return;
            var et = typeof(T);
            if (_fsql.Select<object>().AsType(et).Any()) return;

            var repo = _fsql.GetRepository<object>();
            repo.DbContextOptions.EnableCascadeSave = true;
            repo.DbContextOptions.NoneParameter = true;
            repo.AsType(et);
            repo.Insert(sd);
            lock (sdCopyLock)
                sdCopy = null;
            return;
        }
        #endregion
    }
}
